package com.hycat.mail.order.service.impl;

import com.hycat.mail.common.exception.MailException;
import com.hycat.mail.common.interceptor.AuthInterceptor;
import com.hycat.mail.common.model.ExceptionEnum;
import com.hycat.mail.order.client.CartClient;
import com.hycat.mail.order.client.ProductClient;
import com.hycat.mail.order.client.WareClient;
import com.hycat.mail.order.entity.OrderItemEntity;
import com.hycat.mail.order.service.OrderAccountService;
import com.hycat.mail.order.service.OrderItemService;
import com.hycat.mail.order.to.OrderCreatTo;
import com.hycat.mail.order.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hycat.mail.common.utils.PageUtil;
import com.hycat.mail.common.utils.Query;

import com.hycat.mail.order.dao.OrderDao;
import com.hycat.mail.order.entity.OrderEntity;
import com.hycat.mail.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    private final static Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Autowired
    private ProductClient productClient;

    @Autowired
    private CartClient cartClient;

    @Autowired
    private WareClient wareClient;

    @Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OrderAccountService orderAccountService;

    @Autowired
    private OrderItemService orderItemService;

    @Override
    public PageUtil queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtil(page);
    }

    @Override
    public OrderVo orderView() {
        OrderVo orderVo = new OrderVo();

        //异步丢失threadLocal数据
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        //1.购物车信息 + 四大基本属性
        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            CartVo cartVo = cartClient.listOrderCart(AuthInterceptor.threadLocal.get().getId());
            orderVo.setOrderList(cartVo.getItems());
            orderVo.setTotalNum(cartVo.getTotalNum());
            orderVo.setTotalPrice(cartVo.getTotalPrice());
            orderVo.setReducePrice(cartVo.getReduce());
            BigDecimal subtract = orderVo.getTotalPrice().subtract(orderVo.getReducePrice());
            orderVo.setRealPrice(subtract);
        }, executor);

        //2.地址信息
        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberReceiveAddressVo> address = productClient.listAddress(AuthInterceptor.threadLocal.get().getId());
            orderVo.setAddressList(address);
        }, executor);

        //3.积分信息
        Integer integration = AuthInterceptor.threadLocal.get().getIntegration();
        orderVo.setIntegration(integration);

        CompletableFuture.allOf(cartFuture, addressFuture).join();

        return orderVo;
    }

    @Transactional
    @Override
    public OrderEntity orderPay(OrderSubmitVo vo) {
        try {
            log.info("当前线程Name为 : {}", Thread.currentThread().getName());
            orderAccountService.acquire(AuthInterceptor.threadLocal.get().getId(), "lock");

            //1.创建订单、订单项
            OrderCreatTo orderCreat = orderCreat(vo);

            //2.验价

            //3.保存订单、订单项到数据库
            orderSave(orderCreat);

            //4.锁库存
            lockStock(OrderLockStockVo.from(orderCreat));

            return orderCreat.getOrderEntity();
        } finally {
            log.info("当前线程Name为 : {}", Thread.currentThread().getName());
            orderAccountService.release(AuthInterceptor.threadLocal.get().getId());
        }
    }

    @Override
    public OrderEntity getByOrderSn(String orderSn) {
        return getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
    }

    private synchronized void lockStock(OrderLockStockVo vo) {
        Boolean res = wareClient.orderLockStock(vo);
        //todo 打印库存不足的skuId
        if(!res) {
            throw new MailException(ExceptionEnum.ORDER_WARE_SKU_NOT_ENOUGH);
        }
    }


    private OrderCreatTo orderCreat(OrderSubmitVo vo) {
        OrderCreatTo orderCreat = new OrderCreatTo();

        //1.构建订单项
        List<OrderItemEntity> items = buildOrderItems(vo);
        orderCreat.setItems(items);

        //2.构建订单
        OrderEntity orderEntity = buildOrder(vo, items);
        orderCreat.setOrderEntity(orderEntity);

        //3.运费和订单总额
        orderCreat.setFare(orderEntity.getFreightAmount());
        orderCreat.setRealPrice(orderEntity.getPayAmount());

        return orderCreat;
    }

    private void orderSave(OrderCreatTo orderCreat) {
        //(1).保存订单
        save(orderCreat.getOrderEntity());

        //(2).保存订单项
        orderCreat.getItems().forEach((obj) -> {
            orderItemService.save(obj);
        });
    }

    private List<OrderItemEntity> buildOrderItems(OrderSubmitVo vo) {
        ArrayList<OrderItemEntity> list = new ArrayList<>();
        //(1).

        return list;
    }

    private OrderEntity buildOrder(OrderSubmitVo vo, List<OrderItemEntity> items) {
        OrderEntity orderEntity = new OrderEntity();
        //(1).

        return orderEntity;
    }
}